#pragma once

#include <linux/types.h>
#include <linux/rbtree_types.h>
#include <linux/hrtimer_types.h>

struct sched_dl_entity;

struct sched_rt_entity
{
    struct list_head run_list;
    unsigned long timeout;
    struct sched_rt_entity *back;
    short prio;
    unsigned char on_rq;
    unsigned short on_list;
    unsigned int time_slice;
};

struct load_weight
{
    unsigned long weight;
    unsigned long inv_weight;
};

struct sched_avg
{
    u64 last_update_time;
    u64 load_sum;
    u64 runnable_sum;
    u32 util_sum;
    u32 period_contrib;
    unsigned long load_avg;
    unsigned long runnable_avg;
    unsigned long util_avg;
    unsigned int util_est;
};

struct sched_entity
{
    /* For load-balancing: */
    struct load_weight load;
    struct rb_node run_node;
    u64 deadline;
    u64 min_vruntime;
    u64 vruntime;
    u64 slice;
    u64 min_slice;
    u64 exec_start;
    u64 sum_exec_runtime;
    u64 prev_sum_exec_runtime;
    union
    {
        /*
         * When !@on_rq this field is vlag.
         * When cfs_rq->curr == se (which implies @on_rq)
         * this field is vprot. See protect_slice().
         */
        s64 vlag;
        u64 vprot;
    };

    unsigned char sched_delayed;
    unsigned char on_rq;
    unsigned char rel_deadline;
    unsigned char custom_slice;

    /*
     * Per entity load average tracking.
     *
     * Put into separate cache line so it does not
     * collide with read-mostly values above.
     */
    struct sched_avg avg;

    struct list_head group_node;
};

typedef bool (*dl_server_has_tasks_f)(struct sched_dl_entity *);
typedef struct task_struct *(*dl_server_pick_f)(struct sched_dl_entity *);

struct sched_dl_entity
{
    struct rb_node rb_node;
    u64 deadline; /* Absolute deadline for this instance	*/

    /*
     * Some bool flags:
     *
     * @dl_throttled tells if we exhausted the runtime. If so, the
     * task has to wait for a replenishment to be performed at the
     * next firing of dl_timer.
     *
     * @dl_yielded tells if task gave up the CPU before consuming
     * all its available runtime during the last job.
     *
     * @dl_non_contending tells if the task is inactive while still
     * contributing to the active utilization. In other words, it
     * indicates if the inactive timer has been armed and its handler
     * has not been executed yet. This flag is useful to avoid race
     * conditions between the inactive timer handler and the wakeup
     * code.
     *
     * @dl_overrun tells if the task asked to be informed about runtime
     * overruns.
     *
     * @dl_server tells if this is a server entity.
     *
     * @dl_defer tells if this is a deferred or regular server. For
     * now only defer server exists.
     *
     * @dl_defer_armed tells if the deferrable server is waiting
     * for the replenishment timer to activate it.
     *
     * @dl_server_active tells if the dlserver is active(started).
     * dlserver is started on first cfs enqueue on an idle runqueue
     * and is stopped when a dequeue results in 0 cfs tasks on the
     * runqueue. In other words, dlserver is active only when cpu's
     * runqueue has atleast one cfs task.
     *
     * @dl_defer_running tells if the deferrable server is actually
     * running, skipping the defer phase.
     */
    unsigned int dl_throttled : 1;
    unsigned int dl_yielded : 1;
    unsigned int dl_non_contending : 1;
    unsigned int dl_overrun : 1;
    unsigned int dl_server : 1;
    unsigned int dl_server_active : 1;
    unsigned int dl_defer : 1;
    unsigned int dl_defer_armed : 1;
    unsigned int dl_defer_running : 1;

    unsigned int flags;

    /*
     * Bandwidth enforcement timer. Each -deadline task has its
     * own bandwidth to be enforced, thus we need one timer per task.
     */
    struct hrtimer dl_timer;

    /*
     * Inactive timer, responsible for decreasing the active utilization
     * at the "0-lag time". When a -deadline task blocks, it contributes
     * to GRUB's active utilization until the "0-lag time", hence a
     * timer is needed to decrease the active utilization at the correct
     * time.
     */
    struct hrtimer inactive_timer;

    struct rq *rq;
    dl_server_has_tasks_f server_has_tasks;
    dl_server_pick_f server_pick_task;

    struct sched_dl_entity *pi_se;
    u64 runtime;

    u64 dl_runtime; /* Maximum runtime for each instance	*/
    u64 dl_period;
    u64 dl_deadline;
    u64 dl_bw;
    u64 dl_density; /* dl_runtime / dl_deadline		*/
};
